﻿// ***********************************************************************
// Provided for Informational Purposes Only
//
// Apache 2.0 License
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR 
// PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
//
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.
// ***********************************************************************
// Assembly  : ContractMeow.Api.WinRT
// File      : AuthClient.cs
//
// ***********************************************************************
using ContractMeow.Api.Dtos;
using ContractMeow.WinRT.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace ContractMeow.Api.Clients
{
	public class AuthClient : ClientBase, IAuthClient
	{
		#region Resources
		/// <summary>
		/// The authenticate resource
		/// </summary>
		private const string AuthenticateResource = "/oauth2/access_token.json";

		/// <summary>
		/// The get token resource
		/// </summary>
		private const string GetTokenResource = "/api/v1/oauth/tokens.json";
		#endregion

		#region Ctors
		/// <summary>
		/// Initializes a new instance of the <see cref="AuthClient" /> class.
		/// </summary>
		/// <param name="configuration">The configuration.</param>
		/// <param name="queryStringSerializer">The query string serializer.</param>
		/// <param name="serializer">The serializer.</param>
		/// <param name="deserializer">The deserializer.</param>
		/// <param name="responseErrorHandler">The response error handler.</param>
		/// <param name="proxy">The proxy.</param>
		public AuthClient(IClientConfiguration configuration,
						  IQueryStringSerializer queryStringSerializer,
						  ISerializer serializer,
						  IDeserializer deserializer,
						  IResponseErrorHandler responseErrorHandler,
						  ICookieStore cookieStore,
						  IWebProxy proxy = null)
			: base(configuration, queryStringSerializer, serializer, deserializer, responseErrorHandler, cookieStore, proxy)
		{
			CookieStore = cookieStore;
		}
		#endregion

		/// <summary>
		/// Authenticates the async.
		/// </summary>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <returns>Task{AuthEnvelope}.</returns>
		public async Task<AuthEnvelope> AuthenticateAsync(String username, String password)
		{
			var parameters = new
			{
				username = username,
				password = password,
				client_id = this.Configuration.ClientId,
				client_secret = this.Configuration.ClientSecret
			};

			var r = await PostAsync<AuthEnvelope>(AuthenticateResource, null, parameters);
			return r.Result();
		}

		/// <summary>
		/// Gets the principal async.
		/// </summary>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <returns>Task{Principal}.</returns>
		public async Task<Principal> GetPrincipalAsync(String username, String password)
		{
			AuthEnvelope authEnvelope = await AuthenticateAsync(username, password);

			return authEnvelope == null ? null : new Principal(authEnvelope);
		}

		/// <summary>
		/// Returns all of <see cref="AccessToken"/>s for a given authenticated user.
		/// </summary>
		/// <param name="principal">Current valid user credentials.</param>
		/// <returns></returns>
		public async Task<IList<AccessToken>> GetAllTokensAsync(Principal principal)
		{
			if (principal == null)
				throw new ArgumentNullException("principal");

			var r = await GetAsync<IList<AccessToken>>(GetTokenResource, principal);
			return r.Result();
		}

		/// <summary>
		/// Hydrates the token async.
		/// </summary>
		/// <param name="token">The token.</param>
		/// <returns>Task{AccessToken}.</returns>
		public async Task<AccessToken> HydrateTokenAsync(String token)
		{
			var principal = new Principal { AccessToken = token };

			IList<AccessToken> accessTokens = await GetAllTokensAsync(principal);

			return accessTokens != null && accessTokens.Any()
					   ? accessTokens.First(t => t.Token == token)
					   : null;
		}

		public ICookieStore CookieStore { get; private set; }
	}
}
